package com.checkoutcheckins.server.services;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import oauth.signpost.OAuthConsumer;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;

import com.checkoutcheckins.client.data.foursquare.Category;
import com.checkoutcheckins.client.data.foursquare.Checkin;
import com.checkoutcheckins.client.data.foursquare.FoursquareCheckins;
import com.checkoutcheckins.client.data.foursquare.FoursquareException;
import com.checkoutcheckins.client.data.foursquare.FoursquareUser;
import com.checkoutcheckins.client.data.foursquare.Settings;
import com.checkoutcheckins.client.data.foursquare.User;
import com.checkoutcheckins.client.data.foursquare.Venue;
import com.checkoutcheckins.client.rpc.CheckinResponse;
import com.checkoutcheckins.client.services.FoursquareService;
import com.checkoutcheckins.server.Connection;
import com.checkoutcheckins.server.auth.CheckoutCheckinsOAuth;
import com.checkoutcheckins.server.database.CheckoutCheckinsUser;
import com.checkoutcheckins.server.database.PMF;
import com.google.gson.Gson;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class FoursquareServiceImpl extends RemoteServiceServlet implements
		FoursquareService {

	private static final long serialVersionUID = 6098558931227758812L;

	@Override
	public FoursquareUser getFoursquareUser(String foursquareToken,
			String foursquareSecret) throws IOException, FoursquareException {

		System.out.println("t: " + foursquareToken + " s: " + foursquareSecret);

		FoursquareUser fsUser = null;

		TreeMap<String, String> parameters = new TreeMap<String, String>();
		parameters.put("badges", "1");
		parameters.put("mayor", "1");

		CheckoutCheckinsOAuth checkoutCheckinsOAuth = new CheckoutCheckinsOAuth();
		OAuthConsumer consumer = checkoutCheckinsOAuth.getConsumer();
		consumer.setTokenWithSecret(foursquareToken, foursquareSecret);

		HttpURLConnection request = Connection.getRequest("user", true,
				parameters);
		try {
			consumer.sign(request);
		} catch (OAuthMessageSignerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthExpectationFailedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthCommunicationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		request.connect();

		System.out.println("Response: " + request.getResponseCode() + " "
				+ request.getResponseMessage());

		String jsonString = Connection.parseResponse(request);

		System.out.println(jsonString);

		if (jsonString.contains("error")) {
			FoursquareException fsException = new FoursquareException(
					jsonString);
			throw fsException;
		}

		Gson gson = new Gson();
		User user = gson.fromJson(jsonString, User.class);
		fsUser = user.getFoursquareUser();

		storeUserToDatabase(fsUser, foursquareToken, foursquareSecret);

		setCreatedDate(fsUser.getCheckin());

		System.out.println("name:" + fsUser.getFirstname() + " "
				+ fsUser.getLastname());

		return fsUser;

	}

	@SuppressWarnings("unchecked")
	private void storeUserToDatabase(FoursquareUser fsUser,
			String foursquareToken, String foursquareSecret) {

		PersistenceManager pm = PMF.get().getPersistenceManager();

		pm.makePersistent(fsUser);

		Query query = pm.newQuery(CheckoutCheckinsUser.class);
		query.setFilter("foursquareid == foursquareidParam");
		query.declareParameters("String foursquareidParam");

		System.out.println("querying for foursquare id" + fsUser.getId());

		List<CheckoutCheckinsUser> cociUserList = (List<CheckoutCheckinsUser>) query
				.execute(fsUser.getId());

		if (cociUserList.size() == 0) {
			CheckoutCheckinsUser cociUser = new CheckoutCheckinsUser(fsUser,
					foursquareToken, foursquareSecret);
			pm.makePersistent(cociUser);
		} else {
			CheckoutCheckinsUser checkoutCheckinsUser = cociUserList.get(0);
			checkoutCheckinsUser.setOauthtoken(foursquareToken);
			checkoutCheckinsUser.setOauthsecret(foursquareSecret);
			checkoutCheckinsUser.setLastLoggedIn(new Date());
			pm.makePersistent(checkoutCheckinsUser);
		}

		pm.close();
	}

	@SuppressWarnings("unchecked")
	@Override
	public CheckinResponse getCheckinsFromDatabase(String foursquareId,
			int lastRetrieved) throws FoursquareException, IOException {

		long startTime = System.currentTimeMillis();
		boolean finished = false;
		int recentRetrieved = 0;
		String message = "";
		List<Checkin> dbCheckins = new ArrayList<Checkin>();

		PersistenceManager pm = PMF.get().getPersistenceManager();

		Query query = pm.newQuery(Checkin.class);
		query.setFilter("foursquareid == foursquareidParam");
		query.declareParameters("String foursquareidParam");

		System.out.println("querying for foursquare id" + foursquareId);

		List<Checkin> storedCheckins = (List<Checkin>) query
				.execute(foursquareId);

		boolean timeLimit = false;

		if (storedCheckins.size() > 0) {

			for (int checkinNum = lastRetrieved; checkinNum < storedCheckins
					.size(); checkinNum++) {

				if (System.currentTimeMillis() - startTime < 25000) {
					if (storedCheckins.get(checkinNum).getVenueid() != null) {

						Venue storedVenue = pm.getObjectById(Venue.class,
								storedCheckins.get(checkinNum).getVenueid());

						storedCheckins.get(checkinNum).setVenue(storedVenue);

						if (storedVenue.getCategoryId() != null) {
							Category storedCategory = pm
									.getObjectById(Category.class, storedVenue
											.getCategoryId());
							storedCheckins.get(checkinNum).getVenue()
									.setPrimarycategory(storedCategory);
						}
					}
					dbCheckins.add(storedCheckins.get(checkinNum));
					recentRetrieved = checkinNum;
				} else {
					timeLimit = true;
					message = "Retrieved " + dbCheckins.size()
							+ " stored checkins";
					System.out.println("breaking");
					break;
				}
			}

			if (!timeLimit) {
				System.out.println("Didn't hit time limit. "
						+ dbCheckins.size());
				message = "Retrieved " + dbCheckins.size() + " stored checkins";
				finished = true;
			}
		} else {
			message = "No stored checkins retrieved";
			finished = true;
		}

		pm.close();

		CheckinResponse checkinResponse = new CheckinResponse();
		checkinResponse.setLastRetrieved(recentRetrieved);
		checkinResponse.setCheckinList(dbCheckins);
		checkinResponse.setFinished(finished);
		checkinResponse.setMessage(message);
		checkinResponse.setFoursquareId(foursquareId);

		return checkinResponse;
	}

	public CheckinResponse getCheckinsFromFoursquare(String foursquareId)
			throws IOException, FoursquareException {

		List<Checkin> newCheckins = new ArrayList<Checkin>();
		List<Checkin> storedCheckins = new ArrayList<Checkin>();

		long startTime = System.currentTimeMillis();
		boolean finished = false;
		String message = "";

		PersistenceManager pm = PMF.get().getPersistenceManager();

		System.out.println("Querying with: " + foursquareId);

		CheckoutCheckinsUser checkoutCheckinsUser = pm.getObjectById(
				CheckoutCheckinsUser.class, foursquareId);

		String lastRetrieved = checkoutCheckinsUser.getLastcheckinid();

		newCheckins = getFoursquareCheckins(checkoutCheckinsUser
				.getOauthtoken(), checkoutCheckinsUser.getOauthsecret(), "50",
				lastRetrieved);

		for (int checkinNum = 0; checkinNum < newCheckins.size(); checkinNum++) {

			if (System.currentTimeMillis() - startTime < 25000) {

				Checkin checkin = newCheckins.get(checkinNum);

				if (checkin.getVenue() != null
						&& checkin.getVenue().getId() != null) {
					checkin.setVenueid(checkin.getVenue().getId());
					pm.makePersistent(checkin.getVenue());

					if (checkin.getVenue().getPrimarycategory() != null) {
						checkin.getVenue()
								.setCategoryId(
										checkin.getVenue().getPrimarycategory()
												.getId());
						pm.makePersistent(checkin.getVenue()
								.getPrimarycategory());
					}
				}

				checkin.setFoursquareid(foursquareId);
				pm.makePersistent(checkin);
				storedCheckins.add(checkin);

				if (Long.parseLong(checkin.getId()) > Long
						.parseLong(lastRetrieved)) {
					lastRetrieved = checkin.getId();
				}
			} else {
				System.out.println("breaking");
				break;
			}
		}

		if (newCheckins.size() == 0) {
			message = "Finished retrieving checkins from foursquare";
			finished = true;
		} else {
			message = "Retrieved " + storedCheckins.size()
					+ " foursquare checkins";
		}

		System.out.println("newCheckinsSize: " + storedCheckins.size());

		checkoutCheckinsUser.setLastcheckinid(lastRetrieved);
		System.out.println("setting last checkin id to: " + lastRetrieved);
		pm.makePersistent(checkoutCheckinsUser);
		pm.close();

		CheckinResponse checkinResponse = new CheckinResponse();
		checkinResponse.setFoursquareId(foursquareId);
		checkinResponse.setCheckinList(storedCheckins);
		checkinResponse.setFinished(finished);
		checkinResponse.setMessage(message);

		return checkinResponse;

	}

	private void setCreatedDates(FoursquareCheckins fsCheckins) {

		for (Checkin checkin : fsCheckins.getCheckins()) {
			setCreatedDate(checkin);
		}
	}

	private void setCreatedDate(Checkin checkin) {
		DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yy HH:mm:ss Z");
		try {
			Date date = (Date) formatter.parse(checkin.getCreatedString());
			checkin.setCreatedDate(date);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public List<Checkin> getFoursquareCheckins(String foursquareToken,
			String foursquareSecret, String numberOfCheckins, String sinceId)
			throws IOException, FoursquareException {
		FoursquareCheckins fsCheckins = null;

		CheckoutCheckinsOAuth checkoutCheckinsOAuth = new CheckoutCheckinsOAuth();
		OAuthConsumer consumer = checkoutCheckinsOAuth.getConsumer();
		consumer.setTokenWithSecret(foursquareToken, foursquareSecret);

		TreeMap<String, String> parameters = new TreeMap<String, String>();
		parameters.put("l", numberOfCheckins);
		parameters.put("sinceid", sinceId);

		System.out.println("sinceid from: " + sinceId);

		try {

			HttpURLConnection request = Connection.getRequest("history", true,
					parameters);
			consumer.sign(request);
			request.connect();

			System.out.println("Response: " + request.getResponseCode() + " "
					+ request.getResponseMessage());

			String jsonString = Connection.parseResponse(request);

			System.out.println(jsonString);

			if (jsonString.contains("error")) {
				FoursquareException fsException = new FoursquareException(
						jsonString);
				throw fsException;
			}

			if (jsonString.equals("{\"checkins\":\"\"}")) {
				System.out.println("empty");
				return new ArrayList<Checkin>();
			}

			Gson gson = new Gson();
			fsCheckins = gson.fromJson(jsonString, FoursquareCheckins.class);
			System.out.println("Setting created dates");
			setCreatedDates(fsCheckins);

		} catch (OAuthMessageSignerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthExpectationFailedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthCommunicationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// TODO Auto-generated method stub
		return fsCheckins.getCheckins();

	}

	public List<Checkin> getFoursquareFriendsCheckins(String foursquareToken,
			String foursquareSecret) throws IOException, FoursquareException {
		FoursquareCheckins fsCheckins = null;

		CheckoutCheckinsOAuth checkoutCheckinsOAuth = new CheckoutCheckinsOAuth();
		OAuthConsumer consumer = checkoutCheckinsOAuth.getConsumer();
		consumer.setTokenWithSecret(foursquareToken, foursquareSecret);

		try {

			HttpURLConnection request = Connection.getRequest("checkins", true,
					null);
			consumer.sign(request);
			request.connect();

			System.out.println("Response: " + request.getResponseCode() + " "
					+ request.getResponseMessage());

			String jsonString = Connection.parseResponse(request);

			System.out.println(jsonString);

			if (jsonString.contains("error")) {
				FoursquareException fsException = new FoursquareException(
						jsonString);
				throw fsException;
			}

			if (jsonString.equals("{\"checkins\":\"\"}")) {
				System.out.println("empty");
				return new ArrayList<Checkin>();
			}

			Gson gson = new Gson();
			fsCheckins = gson.fromJson(jsonString, FoursquareCheckins.class);
			System.out.println("Setting created dates");
			setCreatedDates(fsCheckins);

		} catch (OAuthMessageSignerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthExpectationFailedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthCommunicationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// TODO Auto-generated method stub
		return fsCheckins.getCheckins();

	}

	@Override
	public CheckinResponse getFriendsCheckinsFromFoursquare(String foursquareId)
			throws FoursquareException, IOException {

		PersistenceManager pm = PMF.get().getPersistenceManager();

		CheckoutCheckinsUser checkoutCheckinsUser = pm.getObjectById(
				CheckoutCheckinsUser.class, foursquareId);

		List<Checkin> newCheckins = getFoursquareFriendsCheckins(
				checkoutCheckinsUser.getOauthtoken(), checkoutCheckinsUser
						.getOauthsecret());

		CheckinResponse response = new CheckinResponse();
		response.setFinished(true);
		response.setFoursquareId(foursquareId);
		response.setCheckinList(newCheckins);
		response.setMessage("Retrieved friends checkins");

		return response;
	}

	@Override
	public Boolean sendShoutMessageToFoursquare(String foursquareId,
			String message, boolean twitter, boolean facebook)
			throws FoursquareException, IOException {

		PersistenceManager pm = PMF.get().getPersistenceManager();

		CheckoutCheckinsUser checkoutCheckinsUser = pm.getObjectById(
				CheckoutCheckinsUser.class, foursquareId);

		Settings settings = pm.getObjectById(Settings.class, foursquareId);
		settings.setWordSpreadAsked(true);

		pm.makePersistent(settings);
		pm.close();

		CheckoutCheckinsOAuth checkoutCheckinsOAuth = new CheckoutCheckinsOAuth();
		OAuthConsumer consumer = checkoutCheckinsOAuth.getConsumer();
		consumer.setTokenWithSecret(checkoutCheckinsUser.getOauthtoken(),
				checkoutCheckinsUser.getOauthsecret());

		TreeMap<String, String> parameters = new TreeMap<String, String>();

		if (facebook == true) {
			parameters.put("facebook", "1");
		}
		if (twitter == true) {
			parameters.put("twitter", "1");
		}

		parameters.put("shout", URLEncoder.encode(message, "UTF-8"));

		try {

			HttpURLConnection request = Connection.getPost("checkin", true,
					parameters);
			consumer.sign(request);
			request.connect();

			System.out.println("Response: " + request.getResponseCode() + " "
					+ request.getResponseMessage());

			String jsonString = Connection.parseResponse(request);

			System.out.println(jsonString);

			if (jsonString.contains("error")) {
				FoursquareException fsException = new FoursquareException(
						jsonString);
				throw fsException;
			}

		} catch (OAuthMessageSignerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthExpectationFailedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthCommunicationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// TODO Auto-generated method stub
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Settings getUserSettings(String foursquareId) {
		
		PersistenceManager pm = PMF.get().getPersistenceManager();

		Query query = pm.newQuery(Settings.class);
		query.setFilter("foursquareId == foursquareIdParam");
		query.declareParameters("String foursquareIdParam");

		List<Settings> settingsList = (List<Settings>) query
				.execute(foursquareId);

		if (settingsList.size() == 0) {
			Settings settings = new Settings();
			settings.setFoursquareId(foursquareId);
			pm.makePersistent(settings);
			pm.close();
			return settings;
		} else {
			return settingsList.get(0);
		}
	}

	@Override
	public boolean isWordSpreadAsked(String foursquareId,
			boolean wordSpreadAsked) {
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Settings settings = pm.getObjectById(Settings.class, foursquareId);
		settings.setWordSpreadAsked(true);
		
		pm.makePersistent(settings);
		pm.close();
		
		return true;

	}

}
